{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "#### random \"symbolic expression\" generator"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "def Cal(x1,x2,operator:str):\n",
    "    # remap str value stored in tree to calculate operations\n",
    "    if operator=='+':\n",
    "        return x1+x2\n",
    "    if operator=='-':\n",
    "        return x1+x2\n",
    "    if operator=='*':\n",
    "        return x1*x2\n",
    "    if operator=='/': \n",
    "        return x1/x2\n",
    "    # todo:other calculas\n",
    "\n",
    "##ExpressionTree: An abstract expression in tree structure, like (x1+x2)*x3,all numbers in the root node mean index of X,\n",
    "# and all operator(str) in non-root node mean operation. X is waiting to be given to be calculated for a certain expression.\n",
    "\n",
    "# Note: max number in the tree(0-max_num) should not out of index of list X. \n",
    "class ExpressionTreeNode:\n",
    "    def __init__(self,data=None) -> None:\n",
    "        self.left = None\n",
    "        self.right = None\n",
    "        self.data =data\n",
    "    def result(self,X:list) -> float:\n",
    "        if self.left!=None and self.right!=None:\n",
    "            if self.data=='/' and self.right.result(X)==0:\n",
    "                raise ZeroDivisionError\n",
    "            else:\n",
    "                return Cal(self.left.result(X),self.right.result(X),self.data)\n",
    "        else:\n",
    "            return X[self.data]\n",
    "    def show(self)->str:\n",
    "        \"\"\"show expression\n",
    "        \"\"\"\n",
    "        str_show=''\n",
    "        if type(self.data)!=str:\n",
    "            #equal:self.data is num or self is root node or .left .right is None\n",
    "            return 'X'+str(self.data)\n",
    "        else:\n",
    "            if self.data=='+' or self.data =='-':\n",
    "                return '('+self.left.show()+self.data+self.right.show()+')'\n",
    "            else:\n",
    "                return self.left.show()+self.data+self.right.show()\n",
    "\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'\\n# an instance: (x1*x2)+(x3/x4)\\ntree1=ExpressionTreeNode(\\'+\\')\\ntree1.left=ExpressionTreeNode(\\'*\\')\\ntree1.left.left=ExpressionTreeNode(1)\\ntree1.left.right=ExpressionTreeNode(2)\\ntree1.right=ExpressionTreeNode(\\'/\\')\\ntree1.right.left=ExpressionTreeNode(3)\\ntree1.right.right=ExpressionTreeNode(4)\\n\\nimport numpy as np\\nX=np.random.rand(5)\\nprint(\"X\",X)\\nprint(\"tree1.result(X)\",tree1.result(X))\\nx0,x1,x2,x3,x4=X\\nprint(\"(x1*x2)+(x3/x4)\",(x1*x2)+(x3/x4))\\n'"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "'''\n",
    "# an instance: (x1*x2)+(x3/x4)\n",
    "tree1=ExpressionTreeNode('+')\n",
    "tree1.left=ExpressionTreeNode('*')\n",
    "tree1.left.left=ExpressionTreeNode(1)\n",
    "tree1.left.right=ExpressionTreeNode(2)\n",
    "tree1.right=ExpressionTreeNode('/')\n",
    "tree1.right.left=ExpressionTreeNode(3)\n",
    "tree1.right.right=ExpressionTreeNode(4)\n",
    "\n",
    "import numpy as np\n",
    "X=np.random.rand(5)\n",
    "print(\"X\",X)\n",
    "print(\"tree1.result(X)\",tree1.result(X))\n",
    "x0,x1,x2,x3,x4=X\n",
    "print(\"(x1*x2)+(x3/x4)\",(x1*x2)+(x3/x4))\n",
    "'''"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "\"报错原因：每个根节点的类型也应该是ExpressionTreeNode，否则不能进行result运算\\n\\nn2=ExpressionTreeNode()\\nn2.left=1\\nn2.right=2\\nn2.data='+'\\nn2.result([1,2])\""
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "'''报错原因：每个根节点的类型也应该是ExpressionTreeNode，否则不能进行result运算\n",
    "\n",
    "n2=ExpressionTreeNode()\n",
    "n2.left=1\n",
    "n2.right=2\n",
    "n2.data='+'\n",
    "n2.result([1,2])'''"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [],
   "source": [
    "#### random \"symbolic expression\" generator\n",
    "import numpy as np\n",
    "class  RandomExpreesionGenerator:\n",
    "    def __init__(self,complexity:int,max_index:int,opList:list) -> None:\n",
    "        \"\"\"a generator use to generate a random expression used to test fitter.\n",
    "\n",
    "        Args:\n",
    "            complexity (int): number to constrain complexity,temp is max oper times.\n",
    "            max_index (int):constain max X's index,eg.[x0,x1,x2],3 is not allowed.\n",
    "            opList (list): list of operation allowed to use\n",
    "        \"\"\"\n",
    "\n",
    "        \n",
    "        self.complexity=complexity\n",
    "        self.max_index=max_index\n",
    "        self.opList=opList\n",
    "\n",
    "        self.len_OpeL=len(opList)\n",
    "        self.tree_main = ExpressionTreeNode()\n",
    "    def generate(self):\n",
    "        last_node =self.tree_main\n",
    "        import random\n",
    "\n",
    "        for i in range(self.complexity):\n",
    "            if i!=self.complexity-1:\n",
    "                last_node.data=self.opList[random.randint(0,self.len_OpeL-1)]\n",
    "                last_node.right=ExpressionTreeNode(random.randint(0,self.max_index-1))\n",
    "                last_node.left=ExpressionTreeNode()\n",
    "                last_node=last_node.left\n",
    "            else:\n",
    "                last_node.data=self.opList[random.randint(0,self.len_OpeL-1)]\n",
    "                last_node.left=ExpressionTreeNode(random.randint(0,self.max_index-1))\n",
    "                last_node.right=ExpressionTreeNode(random.randint(0,self.max_index-1))\n",
    "    def show(self)->str:\n",
    "        print(self.tree_main.show())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(((((X4+X9)/X1-X1)/X6*X1/X7+X0)/X3*X4/X2+X9)/X2*X3-X4)\n"
     ]
    }
   ],
   "source": [
    "# test and demo:\n",
    "X_dim=10\n",
    "tree_complexity=14\n",
    "rpg=RandomExpreesionGenerator(tree_complexity,X_dim,['+','-','*','/'])\n",
    "rpg.generate()\n",
    "rpg.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "\n",
    "datasets_size=20000\n",
    "tr = rpg.tree_main\n",
    "\n",
    "# note: below func can only generate between [0,1] \n",
    "X = np.random.random([datasets_size,X_dim])\n",
    "Y=[]\n",
    "for ind,x in enumerate(X):\n",
    "    del_times=0\n",
    "    ind-=del_times\n",
    "    try:\n",
    "        y = tr.result(x)\n",
    "        Y.append(y)\n",
    "    except ZeroDivisionError:\n",
    "        X = np.delete(X,ind,axis=0)\n",
    "        del_times+=1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "((20000, 10), 20000)"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# import numpy as np\n",
    "\n",
    "# M=np.random.random([2,3])\n",
    "# M\n",
    "# for ind,i in enumerate(M):\n",
    "#     print('ind',ind,'i',i)\n",
    "#     M = np.delete(M,ind,axis=0)\n",
    "#     print('M',M)\n",
    "#     # 遍历过程中，ind和i不会动态变化\n",
    "\n",
    "X.shape,len(Y)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "ename": "ModuleNotFoundError",
     "evalue": "No module named 'keras'",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mModuleNotFoundError\u001b[0m                       Traceback (most recent call last)",
      "\u001b[1;32mc:\\Users\\hua'wei\\Desktop\\iai\\AI\\Learning-test\\try2.ipynb 单元格 9\u001b[0m line \u001b[0;36m3\n\u001b[0;32m      <a href='vscode-notebook-cell:/c%3A/Users/hua%27wei/Desktop/iai/AI/Learning-test/try2.ipynb#X23sZmlsZQ%3D%3D?line=0'>1</a>\u001b[0m \u001b[39m# # as now we have datasets, we can go further to train and test models.\u001b[39;00m\n\u001b[1;32m----> <a href='vscode-notebook-cell:/c%3A/Users/hua%27wei/Desktop/iai/AI/Learning-test/try2.ipynb#X23sZmlsZQ%3D%3D?line=2'>3</a>\u001b[0m \u001b[39mimport\u001b[39;00m \u001b[39mkeras\u001b[39;00m\n",
      "\u001b[1;31mModuleNotFoundError\u001b[0m: No module named 'keras'"
     ]
    }
   ],
   "source": [
    "# # as now we have datasets, we can go further to train and test models.\n",
    "\n",
    "import torch\n",
    "# model = torch.nn.\n",
    "# model.train(X_train,y_train)\n",
    "# model.test(X_test,y_test)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "env4dl",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.16"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
